/**
 * 密码强度检测工具
 */

export enum PasswordStrengthLevel {
  VERY_WEAK = 0,
  WEAK = 1,
  MEDIUM = 2,
  STRONG = 3,
  VERY_STRONG = 4
}

export interface PasswordStrengthResult {
  score: number // 0-100
  level: PasswordStrengthLevel
  levelText: string
  suggestions: string[]
  crackTime: string
  details: {
    length: number
    hasLowercase: boolean
    hasUppercase: boolean
    hasNumbers: boolean
    hasSpecialChars: boolean
    hasCommonPatterns: boolean
    entropy: number
  }
}

/**
 * 检测密码强度
 */
export function checkPasswordStrength(password: string): PasswordStrengthResult {
  const details = {
    length: password.length,
    hasLowercase: /[a-z]/.test(password),
    hasUppercase: /[A-Z]/.test(password),
    hasNumbers: /[0-9]/.test(password),
    hasSpecialChars: /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password),
    hasCommonPatterns: hasCommonPatterns(password),
    entropy: calculateEntropy(password)
  }

  let score = 0
  const suggestions: string[] = []

  // 长度评分 (最高40分)
  if (details.length < 6) {
    score += details.length * 3
    suggestions.push('密码长度至少应为8位')
  } else if (details.length < 8) {
    score += 18 + (details.length - 6) * 4
    suggestions.push('建议密码长度至少为12位')
  } else if (details.length < 12) {
    score += 26 + (details.length - 8) * 2
  } else if (details.length < 16) {
    score += 34 + (details.length - 12)
  } else {
    score += 40
  }

  // 字符类型多样性 (最高30分)
  let charTypeCount = 0
  if (details.hasLowercase) {
    charTypeCount++
    score += 7
  } else {
    suggestions.push('添加小写字母')
  }

  if (details.hasUppercase) {
    charTypeCount++
    score += 7
  } else {
    suggestions.push('添加大写字母')
  }

  if (details.hasNumbers) {
    charTypeCount++
    score += 7
  } else {
    suggestions.push('添加数字')
  }

  if (details.hasSpecialChars) {
    charTypeCount++
    score += 9
  } else {
    suggestions.push('添加特殊字符(如 !@#$%^&*)')
  }

  // 熵值评分 (最高20分)
  const entropyScore = Math.min(details.entropy / 6, 20)
  score += entropyScore

  // 常见模式检查 (扣分项)
  if (details.hasCommonPatterns) {
    score -= 20
    suggestions.push('避免使用常见的密码模式')
  }

  // 重复字符检查
  const repetitionPenalty = checkRepetition(password)
  score -= repetitionPenalty
  if (repetitionPenalty > 0) {
    suggestions.push('避免使用重复字符')
  }

  // 连续字符检查
  const sequencePenalty = checkSequence(password)
  score -= sequencePenalty
  if (sequencePenalty > 0) {
    suggestions.push('避免使用连续字符(如abc、123)')
  }

  // 限制分数范围
  score = Math.max(0, Math.min(100, score))

  // 确定强度等级
  let level: PasswordStrengthLevel
  let levelText: string

  if (score < 20) {
    level = PasswordStrengthLevel.VERY_WEAK
    levelText = '非常弱'
  } else if (score < 40) {
    level = PasswordStrengthLevel.WEAK
    levelText = '弱'
  } else if (score < 60) {
    level = PasswordStrengthLevel.MEDIUM
    levelText = '中等'
  } else if (score < 80) {
    level = PasswordStrengthLevel.STRONG
    levelText = '强'
  } else {
    level = PasswordStrengthLevel.VERY_STRONG
    levelText = '非常强'
  }

  // 计算破解时间
  const crackTime = estimateCrackTime(password, details.entropy)

  return {
    score,
    level,
    levelText,
    suggestions: suggestions.slice(0, 3), // 只返回前3条建议
    crackTime,
    details
  }
}

/**
 * 计算密码熵值
 */
function calculateEntropy(password: string): number {
  const length = password.length
  if (length === 0) return 0

  let charsetSize = 0

  if (/[a-z]/.test(password)) charsetSize += 26 // 小写字母
  if (/[A-Z]/.test(password)) charsetSize += 26 // 大写字母
  if (/[0-9]/.test(password)) charsetSize += 10 // 数字
  if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) charsetSize += 32 // 特殊字符

  // 熵值 = log2(字符集大小 ^ 密码长度)
  return Math.log2(Math.pow(charsetSize, length))
}

/**
 * 估算破解时间
 */
function estimateCrackTime(password: string, entropy: number): string {
  // 假设每秒可以尝试10亿次(现代GPU的暴力破解速度)
  const attemptsPerSecond = 1e9
  const possibleCombinations = Math.pow(2, entropy)
  const secondsToCrack = possibleCombinations / (2 * attemptsPerSecond)

  if (secondsToCrack < 1) return '瞬间'
  if (secondsToCrack < 60) return `${Math.ceil(secondsToCrack)}秒`
  if (secondsToCrack < 3600) return `${Math.ceil(secondsToCrack / 60)}分钟`
  if (secondsToCrack < 86400) return `${Math.ceil(secondsToCrack / 3600)}小时`
  if (secondsToCrack < 2592000) return `${Math.ceil(secondsToCrack / 86400)}天`
  if (secondsToCrack < 31536000) return `${Math.ceil(secondsToCrack / 2592000)}个月`
  if (secondsToCrack < 3153600000) return `${Math.ceil(secondsToCrack / 31536000)}年`
  return '几个世纪'
}

/**
 * 检查常见密码模式
 */
function hasCommonPatterns(password: string): boolean {
  const commonPasswords = [
    'password', '123456', 'qwerty', 'abc123', 'password123',
    '12345678', '111111', '123123', 'admin', 'letmein',
    'welcome', 'monkey', 'dragon', 'master', 'sunshine',
    'princess', 'football', 'iloveyou', 'superman', 'batman'
  ]

  const lowerPassword = password.toLowerCase()

  return commonPasswords.some(common => lowerPassword.includes(common))
}

/**
 * 检查重复字符
 */
function checkRepetition(password: string): number {
  let maxRepetition = 0
  let currentRepetition = 1

  for (let i = 1; i < password.length; i++) {
    if (password[i] === password[i - 1]) {
      currentRepetition++
      maxRepetition = Math.max(maxRepetition, currentRepetition)
    } else {
      currentRepetition = 1
    }
  }

  // 3个以上重复字符扣10分,每多一个再扣5分
  if (maxRepetition >= 3) {
    return 10 + (maxRepetition - 3) * 5
  }

  return 0
}

/**
 * 检查连续字符
 */
function checkSequence(password: string): number {
  const sequences = [
    'abcdefghijklmnopqrstuvwxyz',
    '0123456789',
    'qwertyuiop',
    'asdfghjkl',
    'zxcvbnm'
  ]

  let penalty = 0

  for (const seq of sequences) {
    // 正向检查
    for (let i = 0; i < seq.length - 2; i++) {
      const subseq = seq.substring(i, i + 3)
      if (password.toLowerCase().includes(subseq)) {
        penalty += 10
      }
    }

    // 反向检查
    const reverseSeq = seq.split('').reverse().join('')
    for (let i = 0; i < reverseSeq.length - 2; i++) {
      const subseq = reverseSeq.substring(i, i + 3)
      if (password.toLowerCase().includes(subseq)) {
        penalty += 10
      }
    }
  }

  return Math.min(penalty, 30) // 最多扣30分
}

/**
 * 生成强密码
 */
export function generateStrongPassword(options: {
  length?: number
  includeUppercase?: boolean
  includeLowercase?: boolean
  includeNumbers?: boolean
  includeSpecialChars?: boolean
  excludeAmbiguous?: boolean
} = {}): string {
  const {
    length = 16,
    includeUppercase = true,
    includeLowercase = true,
    includeNumbers = true,
    includeSpecialChars = true,
    excludeAmbiguous = true
  } = options

  let charset = ''
  const guaranteedChars: string[] = []

  if (includeLowercase) {
    const lowercase = excludeAmbiguous ? 'abcdefghijkmnopqrstuvwxyz' : 'abcdefghijklmnopqrstuvwxyz'
    charset += lowercase
    guaranteedChars.push(lowercase[Math.floor(Math.random() * lowercase.length)])
  }

  if (includeUppercase) {
    const uppercase = excludeAmbiguous ? 'ABCDEFGHJKLMNPQRSTUVWXYZ' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    charset += uppercase
    guaranteedChars.push(uppercase[Math.floor(Math.random() * uppercase.length)])
  }

  if (includeNumbers) {
    const numbers = excludeAmbiguous ? '23456789' : '0123456789'
    charset += numbers
    guaranteedChars.push(numbers[Math.floor(Math.random() * numbers.length)])
  }

  if (includeSpecialChars) {
    const specialChars = excludeAmbiguous ? '!@#$%^&*-_=+' : '!@#$%^&*()_+-=[]{}|;:,.<>?'
    charset += specialChars
    guaranteedChars.push(specialChars[Math.floor(Math.random() * specialChars.length)])
  }

  if (charset.length === 0) {
    throw new Error('至少选择一种字符类型')
  }

  // 生成剩余字符
  const remainingLength = length - guaranteedChars.length
  const randomChars: string[] = []

  for (let i = 0; i < remainingLength; i++) {
    randomChars.push(charset[Math.floor(Math.random() * charset.length)])
  }

  // 合并并打乱
  const allChars = [...guaranteedChars, ...randomChars]
  return shuffleArray(allChars).join('')
}

/**
 * 打乱数组
 */
function shuffleArray<T>(array: T[]): T[] {
  const result = [...array]
  for (let i = result.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [result[i], result[j]] = [result[j], result[i]]
  }
  return result
}

/**
 * 获取密码强度颜色
 */
export function getStrengthColor(level: PasswordStrengthLevel): string {
  switch (level) {
    case PasswordStrengthLevel.VERY_WEAK:
      return '#ff4d4f' // 红色
    case PasswordStrengthLevel.WEAK:
      return '#ff7a45' // 橙红色
    case PasswordStrengthLevel.MEDIUM:
      return '#ffa940' // 橙色
    case PasswordStrengthLevel.STRONG:
      return '#52c41a' // 绿色
    case PasswordStrengthLevel.VERY_STRONG:
      return '#1890ff' // 蓝色
    default:
      return '#d9d9d9' // 灰色
  }
}
